#include"Log.hpp"
#include<queue>
#include<string>
#include<cstdlib>
#include<cassert>
#include<pthread.h>
#include<memory>
#include<iostream>
using namespace std;
#include<unistd.h>

int gThreadNum=5;
template<class T>
class ThreadPool
{
public:
    ThreadPool(int threadNum=gThreadNum):threadNum_(threadNum),isStart_(false)
    {
        pthread_mutex_init(&mutex_,nullptr);
        pthread_cond_init(&cond_,nullptr);
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }

    void push(const T& in)
    {
        lockQueue();
        taskQueue_.push(in);
        choiceThreadForHander();
        unlockQueue();
        //sleep(1);
    }
    static void* threadRoutine(void* args)
    {
        pthread_detach(pthread_self());
        ThreadPool<T>* tp=static_cast<ThreadPool<T>*>(args);
        while(true)
        {
            tp->lockQueue();
            while(!tp->haveTask())
            {
                tp->waitForTask();
            }
            T t=tp->pop();
            tp->unlockQueue();
            int one,two;
            char oper;
            t.get(&one,&two,&oper);
            Log()<<"新线程完成计算任务:"<<one<<oper<<two<<"="<<t.run()<<endl;
            //cout<<"pthread["<<pthread_self()<<"]running……"<<endl;
        }
    }
    void start()
    {
        assert(!isStart_);      //防止线程池被重复启动
        for(int i=0;i<threadNum_;i++)
        {
            pthread_t temp;
            pthread_create(&temp,nullptr,threadRoutine,(void*)this);
        }
        isStart_=true;
    }
private:
    T pop()
    {
        T temp=taskQueue_.front();
        taskQueue_.pop();
        return temp;
    }
    bool haveTask()
    {
        return !taskQueue_.empty();
    }
    void waitForTask()
    {
        pthread_cond_wait(&cond_,&mutex_);
    }
    void lockQueue()
    {
        pthread_mutex_lock(&mutex_);
    }
    void unlockQueue()
    {
        pthread_mutex_unlock(&mutex_);
    }
    void choiceThreadForHander()
    {
        pthread_cond_signal(&cond_);
    }

private:
    bool isStart_;
    int threadNum_;
    queue<T> taskQueue_;
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;
};